package com.sikaryofficial.backend.manager.information;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sikaryofficial.backend.domain.dto.req.music.MusicLibraryListReq;
import com.sikaryofficial.backend.domain.dto.req.music.MusicLibraryReq;
import com.sikaryofficial.backend.domain.dto.resp.music.MusicGenreVO;
import com.sikaryofficial.backend.domain.dto.resp.music.MusicLibraryDTO;
import com.sikaryofficial.backend.domain.entity.Music;
import com.sikaryofficial.backend.domain.entity.MusicGenre;
import com.sikaryofficial.backend.domain.entity.MusicGenreRelation;
import com.sikaryofficial.backend.domain.mapping.MusicLibraryMapping;
import com.sikaryofficial.backend.service.IMusicGenreRelationService;
import com.sikaryofficial.backend.service.IMusicGenreService;
import com.sikaryofficial.backend.service.IMusicService;
import com.sikaryofficial.common.core.constant.CacheBusinessConstants;
import com.sikaryofficial.common.core.exception.ServiceException;
import com.sikaryofficial.common.redis.service.RedisService;
import com.sikaryofficial.common.security.utils.SecurityUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.text.MessageFormat;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author : qinjinyuan
 * @desc : TODO  请填写你的功能描述
 * @date : 2024/08/07 8:36
 */
@Component
@Slf4j
@SuppressWarnings(value = "unchecked")
public class MusicLibraryManager {
    @Autowired
    private IMusicService musicService;
    @Autowired
    private IMusicGenreService musicGenreService;
    @Autowired
    private IMusicGenreRelationService relationService;
    @Autowired
    private RedisService redisService;

    public MusicLibraryDTO getInfo(Long musicId) {
        if (Objects.isNull(musicId)) {
            throw new ServiceException("musicId is null");
        }
        Music music = musicService.getOne(new LambdaQueryWrapper<Music>()
                .eq(Music::getMusicId, musicId)
                .eq(Music::getDeletedVersion, 0L)
        );
        MusicLibraryDTO musicLibraryDTO = MusicLibraryMapping.INSTANCE.coverEntityToDTO(music);
        musicLibraryDTO.setMusicGenreList(musicGenreService.getGenreListByMusicId(musicId));
        return musicLibraryDTO;
    }

    public Long saveOrUpdate(MusicLibraryReq req) {
        Music music = MusicLibraryMapping.INSTANCE.coverReqToEntity(req);
        List<MusicGenreVO> musicGenreList = req.getMusicGenreList();
        if (CollUtil.isEmpty(musicGenreList)) {
            throw new ServiceException("请选择音乐分类");
        }
        if (Objects.isNull(req.getMusicId())) {
            music.setSource(1);
            music.setMusicId(IdWorker.getId());
            music.setCreatedBy(SecurityUtils.getUserId());
            music.setCreatedTime(new Date());
        } else {
            music.setUpdatedBy(SecurityUtils.getUserId());
            music.setUpdatedTime(new Date());
        }
        musicService.saveOrUpdate(music);
        // 参数检查
        List<Long> musicGenreIds = musicGenreList.stream().map(MusicGenreVO::getMusicGenreId)
                .filter(Objects::nonNull).collect(Collectors.toList());
        List<MusicGenre> musicGenres = musicGenreService.list(new LambdaQueryWrapper<MusicGenre>()
                .eq(MusicGenre::getDeletedVersion, 0L)
                .in(MusicGenre::getMusicGenreId, musicGenreIds)
        );
        // 移除在 musicGenreList 中不存在的分类
        musicGenreList.removeIf(musicGenreVO -> musicGenres.stream().map(MusicGenre::getMusicGenreId)
                .noneMatch(musicGenreId -> musicGenreId.equals(musicGenreVO.getMusicGenreId())));
        // 保存分类关系数据
        relationService.batchSaveGenreRelation(musicGenreList, music.getMusicId());
        clearCache();
        return music.getMusicId();
    }

    public void remove(String musicIds) {
        musicService.update(new LambdaUpdateWrapper<Music>()
                .in(Music::getMusicId, musicIds)
                .eq(Music::getDeletedVersion, 0L)
                .set(Music::getUpdatedBy, SecurityUtils.getUserId())
                .set(Music::getUpdatedTime, new Date())
                .setSql(" deleted_version = music_id ")
        );
        relationService.update(new LambdaUpdateWrapper<MusicGenreRelation>()
                .in(MusicGenreRelation::getMusicId, musicIds)
                .eq(MusicGenreRelation::getDeletedVersion, 0L)
                .set(MusicGenreRelation::getUpdatedBy, SecurityUtils.getUserId())
                .set(MusicGenreRelation::getUpdatedTime, new Date())
                .setSql(" deleted_version = relation_id ")
        );
        clearCache();
    }

    public IPage<MusicLibraryDTO> listPage(MusicLibraryListReq req) {
        Page<MusicLibraryDTO> customerPage = new Page<>(req.getPageNum(), req.getPageSize());
        IPage<MusicLibraryDTO> prizePage = musicService.musicBackendPageList(customerPage, req);
        if (CollUtil.isEmpty(prizePage.getRecords())) {
            return new Page<>(1, 7, 0);
        }
        // 添加分类列表数据
        List<MusicLibraryDTO> musicLibraryDTOList = prizePage.getRecords();
        Map<Long, List<MusicGenreVO>> musicGenMapper =
                musicGenreService.getGenreListByMusicIds(musicLibraryDTOList.stream().map(MusicLibraryDTO::getMusicId).collect(Collectors.toList()));
        musicLibraryDTOList.forEach(musicLibraryDTO -> musicLibraryDTO.setMusicGenreList(MapUtils.getObject(musicGenMapper, musicLibraryDTO.getMusicId())));
        return prizePage;
    }

    public IPage<MusicLibraryDTO> listPageForCache(MusicLibraryListReq req) {
        Page<MusicLibraryDTO> customerPage = new Page<>(req.getPageNum(), req.getPageSize());
        // 缓存数据
        String md5 = generateCacheKey(req);
        String cacheKey = MessageFormat.format(CacheBusinessConstants.MUSIC_LIBRARY_CACHE, md5);
        if (Boolean.TRUE.equals(redisService.hasKey(cacheKey))) {
            JSONObject cacheValue = redisService.getCacheObject(cacheKey);
            return Objects.nonNull(cacheValue) ? JSON.parseObject(cacheValue.toString(), new TypeReference<IPage<MusicLibraryDTO>>() {
            }) : null;
        }
        IPage<MusicLibraryDTO> prizePage = musicService.musicPageList(customerPage, req);
        if (CollUtil.isEmpty(prizePage.getRecords())) {
            redisService.setCacheObject(cacheKey, prizePage, 10L, TimeUnit.SECONDS);
            return new Page<>(1, 7, 0);
        } else {
            redisService.setCacheObject(cacheKey, prizePage, 1L, TimeUnit.DAYS);
        }
        return prizePage;
    }

    private String generateCacheKey(MusicLibraryListReq req) {
        String musicGenreIdStr = Objects.nonNull(req.getMusicGenreId()) ? req.getMusicGenreId().toString() : "";
        String title = Objects.nonNull(req.getTitle()) ? req.getTitle() : "";
        return DigestUtil.md5Hex(req.getPageNum() + "_"
                + req.getPageSize() + "_"
                + musicGenreIdStr + "_"
                + title
        );
    }

    /**
     * 清除缓存
     */
    public void clearCache() {
        Collection<String> keys = redisService.keys(CacheBusinessConstants.MUSIC_LIBRARY_CACHE_PREFIX + "*");
        redisService.deleteObject(keys);
    }

    public List<MusicGenreVO> musicGenreList() {
        String cacheKey = CacheBusinessConstants.MUSIC_LIBRARY_GENRE_CACHE;
        if (Boolean.TRUE.equals(redisService.hasKey(cacheKey))) {
            return redisService.getCacheObject(cacheKey);
        }
        List<MusicGenre> musicGenreList = musicGenreService.list(new LambdaQueryWrapper<MusicGenre>()
                .eq(MusicGenre::getDeletedVersion, 0L)
                .orderByDesc(MusicGenre::getGenreCount,MusicGenre::getMusicGenreId)
        );
        List<MusicGenreVO> musicGenreVOList = MusicLibraryMapping.INSTANCE.coverToGenreVO(musicGenreList);
        redisService.setCacheObject(cacheKey, musicGenreVOList, 10L, TimeUnit.MINUTES);
        return musicGenreVOList;
    }
}
